﻿// (c) Copyright Microsoft Corporation.
// This source is subject to the Microsoft Public License (Ms-PL).
// Please see http://go.microsoft.com/fwlink/?LinkID=131993 for details.
// All other rights reserved.

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.IO;
using System.Threading;

using Phidgets;
using Phidgets.Events;

namespace Coding4Fun.Chair.Robot
{
    public class RelayController : IDisposable
    {
        private readonly InterfaceKit _relayController;
        private const int TotalRelays = 4;
        private const int ThreadTick = 10;
        readonly AutoResetEvent _waitForLoad = new AutoResetEvent(false); // prevent race event to be sure phidgets fully loaded and online
        private readonly Dictionary<int, int> _timeDelays;

        public RelayController()
        {
            CopyOsPhidgetDll(); // must be done before you set phidget device

            _relayController = new InterfaceKit();
            _timeDelays = new Dictionary<int, int>();

            _relayController.OutputChange += _relayController_OutputChange;
            _relayController.Attach += _relayController_Attach;
            _waitForLoad.Reset();
            _relayController.open();
        }

        private static bool _isLoaded;
        void _relayController_Attach(object sender, AttachEventArgs e)
        {
            _isLoaded = true;
            _waitForLoad.Set();
        }

        void _relayController_OutputChange(object sender, OutputChangeEventArgs e)
        {
            // closed
            if (!e.Value)
                return;

            ThreadPool.QueueUserWorkItem(state =>
                                             {
                                                 if (_timeDelays.ContainsKey(e.Index))
                                                 {
                                                     while (_timeDelays[e.Index] > 0)
                                                     {
                                                         Thread.Sleep(ThreadTick);
                                                         _timeDelays[e.Index] -= ThreadTick;
                                                     }
                                                 }

                                                 Close(e.Index);
                                             });
        }

        public int GetTimeDelay(int index)
        {
            if (!_timeDelays.ContainsKey(index))
                return 0;

            return _timeDelays[index];
        }

        public void AlterTimeDelay(int index, int autoCloseDelay)
        {
            _timeDelays[index] = autoCloseDelay;
        }

        public void Open(int index, int autoCloseDelay)
        {
            UseRelay(index, true, autoCloseDelay);
        }

        public void Open(Collection<int> indexes, int autoCloseDelay)
        {
            if (indexes == null)
                return;

            foreach (var index in indexes)
                Open(index, autoCloseDelay);
        }

        public void Close(int index)
        {
            UseRelay(index, false, 0);
        }

        public void Close(Collection<int> indexes)
        {
            if (indexes == null)
                return;

            foreach (var index in indexes)
                Close(index);
        }

        private static bool IsValidIndex(int index)
        {
            return (index < TotalRelays || index >= 0);
        }

        private void UseRelay(int index, bool openRelay, int autoCloseDelay)
        {
            if (!IsValidIndex(index) || !_relayController.Attached)
                return;

            if (!_isLoaded)
            {
                _waitForLoad.WaitOne();
            }

            AlterTimeDelay(index, autoCloseDelay);
            _relayController.outputs[index] = openRelay;
        }

        private const string PhidgetFileName = "phidget21";
        private const string PhidgetFullFileName = "phidget21.dll";
        private static void CopyOsPhidgetDll()
        {
            // always copy new
            File.Copy(
                string.Format(
                    "Dependencies/{0}_{1}.dll",
                    //PhidgetFileName, (OsDetect.Is64Bit()) ? "64" : "86"),
                    // for some reason 64 driver has issues with the 0/0/4
                    // reported issue to phidgets
                    PhidgetFileName, "86"),
                    PhidgetFullFileName, true);
        }

        public void Dispose()
        {
            Dispose(true);

            GC.SuppressFinalize(this);
        }

        protected virtual void Dispose(bool disposing)
        {
            _waitForLoad.Dispose();

            if (_relayController == null || !_relayController.Attached)
                return;
            
            _relayController.OutputChange -= _relayController_OutputChange;
            _relayController.Attach -= _relayController_Attach;

            _relayController.close();
        }
    }
}